home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / varia / grammar2.lha / c++grammar2.0 / grammar5 / grammar5.txt < prev    next >
Text File  |  1991-07-11  |  64KB  |  1,446 lines

  1. Copyright (C) 1989.1990, James  A.   Roskind,  All  rights  reserved. 
  2. Abstracting  with credit is permitted.  The contents of this file may 
  3. be reproduced electronically, or in printed  form,  IN  ITS  ENTIRETY 
  4. with  no  changes, providing that this copyright notice is intact and 
  5. applicable in the copy.  No other copying is  permitted  without  the 
  6. expressed written consent of the author.
  7.  
  8. FILENAME: GRAMMAR5.TXT
  9. AUTHOR: Jim Roskind
  10.         Independent Consultant
  11.         516 Latania Palm Drive
  12.         Indialantic FL 32903
  13.         (407)729-4348
  14.         jar@hq.ileaf.com
  15.         or ...!uunet!leafusa!jar
  16.  
  17.  
  18.     A YACC-able C++ 2.1 GRAMMAR, AND THE RESULTING AMBIGUITIES
  19.                                         (Release 2.0 Updated 7/11/91)
  20.  
  21. ABSTRACT
  22.  
  23. This paper describes ambiguous aspects of the C++ language  that  have 
  24. been  exposed by the construction of a YACC-able grammar for C++.  The 
  25. grammar is provided in  a  separate  file,  but  there  are  extensive 
  26. references  to  the  actual  grammar.   This  release  of  the grammar 
  27. includes the output from a  yacc  cross-reference  tool  that  I  have 
  28. written.   The  discussion  in  this file will make many references to 
  29. that verbose output (typically provided in a  file  called  y.output), 
  30. but  the  file  is only critical if you are trying to "check my work", 
  31. rather than read my results.  The  format  of  the  machine  generated 
  32. documentation provided in y.output is defined in autodoc5.txt.
  33.  
  34. This  release  of  the  grammar  provides  what  I believe is complete 
  35. support for nested types, at least syntactically.  It does not support 
  36. either templates, or exception handling,  as  the  discussion  of  the 
  37. syntax for these elements is not finalized.  
  38.  
  39. Theoretical  Note  (skip  if you hate theory): My C++ grammar does not 
  40. make use of the %prec or %assoc features of YACC, and hence  conflicts 
  41. are  never  hidden within my grammar.  The wondrous result is that, to 
  42. the extent to which my grammar can be seen to span the syntax  of  the 
  43. language,  in  all places where YACC reports no conflicts, the grammar 
  44. is a totally unambiguous statement of  the  syntax  of  the  language.  
  45. This  result  is  remarkable  (I think), because the "general case" of 
  46. deciding whether a grammar is ambiguous or not, is equivalent to  (the 
  47. unsolvable) halting problem.
  48.  
  49. Although  this  paper is terse, and at least hastily formed, I believe 
  50. that its content is so significant to my results that  it  had  to  be 
  51. included.   I  am  sorry  that I do not have the time at this point to 
  52. better arrange its contents.
  53.  
  54.  
  55.  
  56.  
  57. CONTENTS
  58.  
  59.     CONTENTS
  60.         INTRODUCTION
  61.         REVIEW: STANDARD LEXICAL ANALYSIS HACK: TYPEDEFname vs IDENTIFIER
  62.         STATUS OF MY "DISAMBIGUATED" GRAMMAR
  63.     SUMMARY OF CONFLICTS
  64.         
  65.     17 EASY CONFLICTS, WITH HAPPY ENDINGS
  66.     1 SR CONFLICT WITH AN ALMOST HAPPY ENDING
  67.         6 NOVEL CONFLICT THAT YIELD TO SEMANTIC DISAMBIGUATION
  68.     1 CONFLICT THAT CONSTRAINTS SUPPORT THE RESOLUTION FOR
  69.     
  70.     THE TOUGH AMBIGUITIES: FUNCTION LIKE CASTS AND COMPANY (17 CONFLICTS)
  71.         THE TOUGH AMBIGUITIES: FUNCTION LIKE CASTS AND COMPANY
  72.     LALR-only CONFLICTS IN THE GRAMMAR
  73.         SAMPLE RESOLUTIONS OF AMBIGUITIES BY MY C++ GRAMMAR
  74.         DIFFICULT AMBIGUITIES FOR C++ 2.0 PARSER TO TRY
  75.         COMMENTARY ON CURRENT C++ DISAMBIGUATING RULES
  76.         SOURCE OF CONFLICTS IN C++ (MIXING TYPES AND EXPRESSIONS)
  77.     FUNCTION LIKE CAST vs DECLARATION AMBIGUITIES
  78.     FUNCTION LIKE CAST vs DECLARATION : THE TOUGH EXAMPLE:        
  79.         
  80.     CONCLUSION
  81.  
  82.     APPENDIX A:
  83.       PROPOSED GRAMMAR MODIFICATIONS (fixing '*', and '&' conflicts)
  84.  
  85.     APPENDIX B:
  86.       CANONICAL DESCRIPTION OF CONFLICTS and STATES
  87.  
  88.  
  89.  
  90.  
  91.  
  92. INTRODUCTION
  93.  
  94. This paper is  intended  to  go  into  significant  detail  about  the 
  95. ambiguities  that I have seen in the C++ 2.1 language (proposed in the 
  96. "C++ Annotated Reference Manual", a.k.a. ARM, by Ellis and Stroustrup) 
  97. and exposed by attempting to develop a YACC compatible (i.e., LALR(1)) 
  98. grammar.  I must point out that this is NOT meant as an attack on  the 
  99. language  or  the  originators  thereof,  but  rather an R&D effort to 
  100. disambiguate some details.  (I personally believe that Stroustrup  et. 
  101. al.  are doing a GREAT job).  I have the vague hope that the extensive 
  102. hacking  that  I have done with YACC on the C++ grammar has given me a 
  103. rather novel vantage point.  (I  have  expressed  my  observations  to 
  104. Bjarne  Stroustrup,  and in doing so verified that other folks had not 
  105. previously  identified  several  of  my  points).   In  light  of   my 
  106. activities,  this  paper  includes  a fair amount of philosophizing. I 
  107. hope that none of this paper assumes too greatly that I  have  insight 
  108. that  is  beyond  that  of  the  readers, and certainly no insults are 
  109. intended.
  110.  
  111. If you like investigating grammars directly (rather than reading  what 
  112. I  have  to say), I would strongly suggest you read the ANSI C grammar 
  113. before looking at the C++  grammar.   Additionally,  if  you  want  to 
  114. really  understand  the  grammar,  as  suggested  in autodoc5.txt, the 
  115. grammar cross-reference provided in y.output is also very helpful. The 
  116. C++ grammar  is  pretty  large,  and  you  can  expect  the  following 
  117. statistics if you have a similar YACC to that I am using:
  118.  
  119. Berkeley YACC (1.8  01/02/91)
  120.  
  121. 103 terminals, 186 nonterminals
  122. 665 grammar rules, 1256 states
  123. 24 shift/reduce conflicts, 18 reduce/reduce conflicts.
  124.  
  125. Sadly,  many  standard  yacc implementations have static limits on the 
  126. grammars that they can handle.  If you  find  this  to  be  a  problem 
  127. (i.e.,  you  yacc  says  "too  many  states", and terminates), I would 
  128. suggest acquiring Berkeley yacc (which is free), or  bison  (which  is 
  129. mostly  free),  or  purchasing  a  commercial  yacc implementation.  A 
  130. simple port of these publicly available sources on  machines  with  16 
  131. bit  "int"s  (e.g.,  most  PCs)  will  also  be  unable to process the 
  132. grammar.  PCYACC (from Abraxas  Software)  and  ydb  (from  Bloomsbury 
  133. Software),  are examples of commercial products that run on the PC and 
  134. Sun respectively, that I know from experience can yacc these  grammars 
  135. (I currently have no financial affiliation with either vendor).
  136.  
  137.  
  138. REVIEW: STANDARD LEXICAL ANALYSIS HACK: TYPEDEFname vs IDENTIFIER
  139.  
  140. This section is targeted at readers that are not familiar with parsing 
  141. C  with a context free grammar.  The reader should note that there are 
  142. two distinct forms of `identifiers' gathered during lexical  analysis, 
  143. and  identified  as  terminal  tokens  in  both  of  my grammars.  The 
  144. terminal tokens are called IDENTIFIER  and  TYPEDEFname  respectively. 
  145. This  distinction  is  a  required  by  a fundamental element of the C 
  146. language.  The definition of a "TYPEDEFname" is a  lexeme  that  looks 
  147. like  a  standard  identifier,  but is currently defined in the symbol 
  148. table as being declared a typedef (or class, struct, enum  tag)  name. 
  149. All  other  lexemes  that appear as identifiers (and are not keywords) 
  150. are tokenized as IDENTIFIERs.  The  remainder  of  this  section  will 
  151. review the motivation for this approach.
  152.  
  153. Consider the following sample code, which uses the C language:
  154.  
  155.         ...
  156.         int main() { f (*a) [4] ; ...
  157.  
  158. Most  readers  will intuitively parse the above sequence as a function 
  159. call to "f", with an argument "*a",  the  return  value  of  which  is 
  160. (probably)  a  pointer,  and  hence  can  be  indexed by "4".  Such an 
  161. interpretation presumes that the prior context was something like:
  162.  
  163.         ...
  164.         extern float *a;
  165.         char * f(float);
  166.         int main() { f (*a) [4] ; ...
  167.  
  168. However, if the prior context was **INSTEAD**:
  169.  
  170.         ...
  171.         typedef int f;
  172.         extern float a;
  173.         int main() { f (*a) [4] ; ...
  174.  
  175. then the interpretation  of  the  code  is  entirely  different.   The 
  176. fragment  in  question  actually redeclares a local variable "a", such 
  177. that the type of "a" is "pointer to array of 4 int's"!  So we  see  in 
  178. this   example   that  the  statement  "f(*a)[4];"  cannot  be  parsed 
  179. independent of context.
  180.  
  181. The standard solution to the above ambiguity is to allow  the  lexical 
  182. analyzer to form different tokens based on contextual information. The 
  183. contextual information that is used is the answer to the question: "Is 
  184. a  given  identifier  defined as a typedef name (or class name) at the 
  185. current point in the parse"?  I will refer to this feedback loop (from 
  186. the parser that stores information in  a  symbol  table,  wherein  the 
  187. lexer extracts the information) as the "lex hack".  With this lex hack 
  188. in  place the code fragment "f(*a)[4];" would be provided by the lexer 
  189. as either:
  190.  
  191.         IDENTIFIER '(' '*' IDENTIFIER ')' '[' INTEGERconstant ']' ';'
  192.  
  193. or
  194.  
  195.         TYPEDEFname '(' '*' IDENTIFIER ')' '[' INTEGERconstant ']' ';'
  196.  
  197. The two case are very easy for a context free grammar to  distinguish, 
  198. and  the  ambiguity  vanishes.  Note that the fact that such a hack is 
  199. used (out of necessity) demonstrates that C  is  not  a  context  free 
  200. language,  but  the hack allows us to continue to use an LR(1) parser, 
  201. and a context free grammar.
  202.  
  203. Note that this hack is, of necessity, also made  use  of  in  the  C++ 
  204. grammar,  but  no  additional  feedback  (a.k.a.:  hack)  is (at least 
  205. currently) required.  The interested reader should also note that this 
  206. feedback loop (re: updating the symbol table) must be  swift,  as  the 
  207. lexical  analyzer  cannot  proceed  very  far  without this contextual 
  208. information.  This constraint on the feedback time often prevents  the 
  209. parser  from  "deferring" actions, and hence increases the pressure on 
  210. the parser to rapidly disambiguate token sequences.
  211.  
  212.  
  213.  
  214. STATUS OF MY "DISAMBIGUATED" GRAMMAR
  215.  
  216. Several independent reviews,  which  provided  a  complete  front  end 
  217. lexical  analyzers,  and  parsed existing C++ code, have verified that 
  218. the grammars span of  the  C++  language  appears  complete.   I  have 
  219. neither   incorporated   parametric   types  (a.k.a.   templates)  nor 
  220. exception handling into the grammars at this point, as  they  continue 
  221. to be in a state of flux.
  222.  
  223. The  grammar does (I believe) support all the features provided in C++ 
  224. 2.1, including multiple inheritance and the  enhanced  operator  "new" 
  225. syntax (includes placement expression). I believe that, except for the 
  226. minor  change  involving  not  permitting parentheses around bit field 
  227. names during a declaration, my C++ grammar supports a superset  of  my 
  228. ANSI  C  grammar. Note that I haven't inline expanded all the rules in 
  229. the C grammar that were required for C++ disambiguation (re: deferring 
  230. reductions), and hence a `diff' of the two grammars will not provide a 
  231. trivial comparison.  The resulting major  advantage  of  this  grammar 
  232. over  every  other  current  C++  parser  (that  I know of) is that it 
  233. supports old style function definitions AS WELL AS  all  the  standard 
  234. C++.   (It is my personal belief that such support was dropped by many 
  235. compilers and translators in order to resolve the many syntax problems 
  236. that appear within C++.  I believe this  grammar  shows  that  such  a 
  237. decision was premature).
  238.  
  239. My  list  of shift-reduce and reduce-reduce conflicts is currently: 24 
  240. shift/reduce, 18 reduce/reduce conflicts reported.  I have  chosen  to 
  241. leave  so  many conflicts in the grammar because I hope to see changes 
  242. to the syntax that will remove them, rather than making changes to  my 
  243. grammar  that  will firmly accept and disambiguate them.  (Considering 
  244. the detailed analysis presented here,  such  changes  would  only  add 
  245. unnecessary complications to an already large grammar).
  246.  
  247.  
  248. SUMMARY OF CONFLICTS
  249.  
  250. The  following  summarizes the conflicts based on a simple description 
  251. of the nature of the conflict:
  252.  
  253. 8 SR caused by operator function name with trailing * or &
  254.     states: 131, 138, 281, 282
  255.  
  256. 8 SR caused by freestore              with trailing * or &
  257.     states: 571, 572, 778, 779
  258.  
  259. 1 SR caused by dangling else and my laziness
  260.     state: 1100
  261.  
  262. 1 SR caused by member declaration of sub-structure, with trailing :
  263.     state: 64
  264.  
  265. 6 RR caused by constructor declaration vs member declaration
  266.     states: 1105, 1152, 1175
  267.  
  268. 1 SR caused by explicit call to destructor, without explicit scope
  269.     state: 536
  270.  
  271.  
  272.  
  273.  
  274. 3 RR caused by function-like cast vs typedef redeclaration ambiguity
  275.     state: 738
  276.  
  277. 3 RR caused by function-like cast vs identifier declaration ambiguity
  278.     state: 739
  279.  
  280. 3 RR caused by destructor declaration vs destructor call 
  281.     state: 740
  282.  
  283. 3 RR caused by parened initializer vs  prototype/typename
  284.     state: 758
  285.  
  286. 5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  287.     states: 395, 621, 1038, 1102, 1103
  288.  
  289.  
  290.  
  291. Of these conflicts, the ones that most C++ parser authors  are  mainly 
  292. concerned  with  the  17  listed  at  the end of the above list.  They 
  293. relate to function-like-cast vs  declaration,  and  redundant  parened 
  294. TYPEDEFname  redeclaration  vs  old  style  cast,  etc.  The following 
  295. sections breeze through the "easy" conflicts, and then talk at  length 
  296. about these tough ones.
  297.  
  298.  
  299.  
  300. 17 EASY CONFLICTS, WITH HAPPY ENDINGS
  301.  
  302. The first group of 17 SR conflicts:
  303.  
  304. 8 SR caused by operator function name with trailing * or &
  305.     states: 131, 138, 281, 282
  306. 8 SR caused by freestore              with trailing * or &
  307.     states: 571, 572, 778, 779
  308. 1 SR caused by dangling else and my laziness
  309.     state: 1100
  310.  
  311. have  very simple resolutions.  If you are reading this, I assume that 
  312. you are already familiar with the  if-if-else  conflict  (it  is  also 
  313. analyzed in depth in the autodoc5.txt file).
  314.  
  315. The  8  conflicts based "freestore with trailing * or &" can be hinted 
  316. at by the example:
  317.  
  318.         a = new int * * object;
  319.  
  320. Is the above the same as:
  321.  
  322.         a = (new int) * (* T);
  323. or:
  324.         a = (new (int *)) * T;
  325.  
  326. As a resolution,  the  "longest  possible  type"  is  isolated  by  my 
  327. grammar.  The result is:
  328.  
  329.         a = (new (int * * )) ...
  330.  
  331. which  leads  to  a  syntax  error  in my example!  This resolution is 
  332. indeed what is quietly specified  for  C++  2.0  (and  implemented  in 
  333. cfront).  The critical statement and example in the C++ 2.0 Ref Man at 
  334. the end of section 5.3.3 makes this resolution clear.
  335.  
  336. The  8 conflicts involving "operator function names with trailing * or 
  337. &" are quite similar to what was just presented.  The critical fact is 
  338. that "operator typename"  is  allowed  in  the  grammar  to  define  a 
  339. function.  Whenever a function is provided, but NOT followed by a '(', 
  340. the  address  of  the  function  is  implicitly  taken and used in the 
  341. expression (see draft ANSI C standard for finer  details).   For  some 
  342. class T, the following MIGHT all be valid statements:
  343.  
  344.         operator T;
  345.         operator T*;
  346.         operator T**;
  347.  
  348. If  the  above  are valid, then the interpretation of the following is 
  349. ambiguous:
  350.  
  351.         operator T * * a;
  352.  
  353. The above might be interpreted as:
  354.  
  355.         (operator T) * (* a);
  356. or
  357.         (operator (T *)) * a;
  358.  
  359. The default LR rules parse the largest possible type, and lead to:
  360.  
  361.         (operator (T * * )) ...
  362.  
  363. which in our example leads to a syntax error.  Here again the "longest 
  364. possible type..." rule supports my grammar.  Note that  this  rule  is 
  365. actually  a  consequence  (in my opinion) of the cfront implementation 
  366. via a YACC grammar, and the default resolution of  conflicts  in  that 
  367. grammar.
  368.  
  369.  
  370.  
  371. 1 SR CONFLICT WITH AN ALMOST HAPPY ENDING
  372.  
  373. 1 SR caused by member declaration of sub-structure, with trailing :
  374.     state: 64
  375.  
  376. Note that this conflict is different from the one isolated in the 6/90 
  377. version of this grammar, that pertained to ':'.
  378.  
  379. The conflict now takes place (as seen in the demonstrations section of 
  380. y.output) in variations of the following program prefix:
  381.  
  382.     class A { class B :
  383.  
  384. The  problem  is  that  "class B" can be a declaration specifier, much 
  385. like "int".  When a bit field is defined, then  "int  :"  provides  an 
  386. unnamed  bit  field  member  of  a  structure.   My grammar avoids the 
  387. reduction of "class B" to declaration specifier in this  context,  and 
  388. hence  disambiguates  in  favor  of  a nested class, with a derivation 
  389. list:
  390.  
  391.     class A { class B : Parent { ..... };};
  392.  
  393. Although this  looks  reasonable  today,  when  template  classes  are 
  394. introduced,  and  the  supplied  type may be "int", then a real syntax 
  395. problem  will  be  present   (hence,   the   almost   happy   ending). 
  396. Specifically,  one  can  image a parameterized type, which is given as 
  397. input (i.e., an argument) either "signed int", or "unsigned int",  and 
  398. then  this  type  might  be  used  as a declaration specifier in a bit 
  399. field.  When the type is referred to during  the  parameterized  class 
  400. elaboration,  the  reference *can* be made in the form "class T", even 
  401. though "T" is simply "signed int".
  402.  
  403. For now (until the template syntax is worked out), the  disambiguation 
  404. provided by this grammar will do very nicely.
  405.  
  406.  
  407.  
  408. 6 NOVEL CONFLICTS THAT YIELD TO SEMANTIC DISAMBIGUATION
  409.  
  410. The  conflicts  that  are discussed in this section have been deferred 
  411. (by A LOT of work, and A LOT of inline expansion) to occur when a ';', 
  412. or a '{' is reached.  At  that  point,  semantic  information  in  the 
  413. tokens can safely be used to decide which of two cases are at hand.
  414.  
  415. The conflicts are referred to as:
  416.  
  417.     6 RR caused by constructor declaration vs member declaration
  418.     states: 1105, 1152, 1175
  419.  
  420.  
  421. occur during a class/struct elaboration.  Consider the following class 
  422. elaborations:
  423.  
  424.         typedef int T1, T2, T3  ;
  425.         class GOO { int a;} ;
  426.         class FOO {
  427.                 GOO    T1  ; // clearly a redefinition of T1
  428.                 FOO  ( T2 ); // clearly a constructor
  429.                 GOO  ( T3 ); // redefinition of T3
  430.                 };
  431.  
  432. Note  that  the  last  two entries in FOO's elaboration "FOO(T2);" and 
  433. "GOO(T3);" are  tokenized  IDENTICALLY,  but  must  have  dramatically 
  434. different  meanings.   When I first found this ambiguity I was hopeful 
  435. that I could extend the lex hack that distinguishes TYPEDEFnames  from 
  436. random  IDENTIFIERs,  and distinguish something like CURRENTCLASSname. 
  437. Unfortunately, the  potential  for  elaborations  within  elaborations 
  438. appears  to  make  such a hack unworkable.  In addition, once I got my 
  439. grammar to defer all such ambiguous cases until a ';' was seen, I felt 
  440. confident that the ambiguity was resolved (and the introduction of  an 
  441. additional "hack" was unnecessary).
  442.  
  443. Note  that  the  situations  are  identical  when a '{' is seen, as it 
  444. presents the start of the body of either a function, or a constructor, 
  445. and an identical decision must be made.
  446.  
  447.  
  448. 1 CONFLICT THAT CONSTRAINTS SUPPORT THE RESOLUTION FOR
  449.  
  450. With  this  new  grammar,  the  ability  to  make  explicit  calls  to 
  451. constructors is supported.  As pointed out in section 12.4 of the ARM, 
  452. the  implicit  use  of  the  "this"  pointer  to  refer  to a specific 
  453. destructor leads to an ambiguity with the unary "~" operation.   As  a 
  454. result, in situations where it is possible to parse a sentence so that 
  455. the "~" is the unary operator, it is done.  The conflict is shown as:
  456.  
  457. 1 SR caused by explicit call to destructor, without explicit scope
  458.     state: 536
  459.  
  460. Note that the reduction:
  461.  
  462.     complex_name : '~' TYPEDEFname 
  463.  
  464. is  what  is  used  to develop a "name" that can be used to refer to a 
  465. destructor  explicitly.   The  decision  is  made  to  not  use   this 
  466. reduction,  in favor of "something else" (which results from a shift). 
  467. Since the only alternative to specifying a destructor is to  make  "~" 
  468. serve as a unary operator, we are assured that we support the standard 
  469. given in the ARM.  Note that this should probably be officially listed 
  470. as  a part of the syntax restrictions, but in any case, it is at least 
  471. a disambiguating constraint, and we are guaranteed to support it.
  472.  
  473.  
  474.  
  475. THE TOUGH AMBIGUITIES: FUNCTION LIKE CASTS AND COMPANY (17 CONFLICTS)
  476.  
  477. The  ambiguities  listed  in  this  section  pertain  to  attempts  to 
  478. distinguish                declaration/types-names                from 
  479. expression-statements/expressions.  For example:
  480.  
  481.     char *b ="external" ; // declare a variable to confuse us :-)
  482.     main () {
  483.         class S;
  484.         S (*b)[5]; // redeclare "b" pointer to array of 5 S's ?
  485.                // OR ELSE indirect through b; cast to S; index using 5 ?
  486.         }
  487.  
  488. The above is what I  call  the  "declaration  vs  function  like  cast 
  489. ambiguity".   Awareness  about  this ambiguity in this context appears 
  490. fairly widespread among C++ parser authors.  The  ARM  makes  explicit 
  491. reference  to  this  problem in section 6.8 "Ambiguity Resolution".  I 
  492. believe the underlying philosophy provided by the Reference Manual  is 
  493. that  if a token stream can be interpreted by an ANSI C compiler to be 
  494. a declaration, then a C++ compiler should disambiguate in favor  of  a 
  495. declaration.  Unfortunately, section 6.8 goes on to say:
  496.  
  497.     "To  disambiguate,  the whole statement may have to be examined to 
  498.     determine if it is an expression-statement, or a declaration.  ... 
  499.     The disambiguation is purely syntactic; that is,  the  meaning  of 
  500.     the  names, beyond whether they are type-names or not, is not used 
  501.     in the disambiguation".
  502.  
  503. The  above  advice  only  forestalls  the  inevitable  ambiguity,  and 
  504. complicates  the  language  in  the process.  The examples that follow 
  505. will demonstrate the difficulties.
  506.  
  507. There are several other contexts where such  ambiguities  (typedef  vs 
  508. expression) arise:
  509.  
  510.         1) Where a statement is valid (as shown above).
  511.         2) As the argument to sizeof()
  512.         3) Following "new", with the C++ syntax allowing a placement
  513.                 expression
  514.         4) Immediately following a left paren  in  an  expression  (it 
  515.                 might be an old style cast, and hence a type name)
  516.         5) Following  a  left paren, arguments to constructors can be 
  517.                 confused with prototype type-names.
  518.         6) Recursively in any of the above,  following  a  left  paren 
  519.                 (what  follows might be argument expressions, or might 
  520.                 be function prototype parameter typing)
  521.  
  522. Examples of simple versions of the sizeof context are:
  523.  
  524.         class T;
  525.         sizeof ( T    ); // sizeof (type-name)
  526.         sizeof ( T[5] ); // again a type name
  527.         sizeof ( T(5) ); // sizeof (expression)
  528.         sizeof ( T()  ); // semantic error: sizeof "function returning T"?
  529.                         // OR ELSE sizeof result of function like cast
  530.  
  531. Examples  of  the  old  style  cast ambiguity context, which are still 
  532. ambiguous when the '(' after the 'T' has been seen:
  533.  
  534.         class T { /* put required declarations here */ 
  535.                 };
  536.         a = (T(      5));  // function like cast of 5
  537.         b = (T(      )) 0; // semantic error: cast of 0 to type "function
  538.                         // returning T"
  539.  
  540. In constructors the following demonstrates the problems:
  541.  
  542.         class T;
  543.         T (b)(int  d ); // same as "T b(int);", a function declaration
  544.         T (d)(int (5)); // same as "T d(5);", an identifier declaration
  545.         T (d)(int ( )); // ambiguous
  546.  
  547. The problem can appear recursively  in  the  following  examples.   By 
  548. "recursively"  I  mean  that an ambiguity in the left-context has made 
  549. the parser unsure of whether an "expression"  or  a  "type"  is  being 
  550. parsed,  and  the ambiguity is continued by the token sequence.  After 
  551. the parser can determine what this subsequence is, it will in turn  be 
  552. able to disambiguating what the prior tokens were.
  553.  
  554. Recursion on the statement/declaration context:
  555.  
  556.         class S;
  557.         class T;
  558.         S (*b)(T); // declare b "pointer to function taking T returning S"
  559.         S (*c)(T dummy); // same declaration as for "b"
  560.         int dummy;
  561.         S (*d)(T (dummy)); // This T might be casting dummy
  562.  
  563. Recursion on the sizeof context is shown in the following examples. As 
  564. before, the examples include semantic errors.
  565.  
  566.         class T;
  567.         class S;
  568.         sizeof ( T(S dummy) ); // sizeof "function taking S returning T"
  569.         int dummy;
  570.         sizeof ( T(S (dummy)) ); // sizeof "function taking S returning T"
  571.                 // OR ELSE cast dummy to S, and then cast that to T, which
  572.                         // is the same as "sizeof T;"
  573.  
  574.  
  575. The  following are the list of conflicts that fall into the categories 
  576. listed above.  To see the complete details of each conflict state  see 
  577. the y.output file supplied with this grammar.
  578.  
  579.  
  580. 3 RR caused by function-like cast vs typedef redeclaration ambiguity
  581.     state: 738
  582.  
  583. 3 RR caused by function-like cast vs identifier declaration ambiguity
  584.     state: 739
  585.  
  586. 3 RR caused by destructor declaration vs destructor call 
  587.     state: 740
  588.  
  589. 3 RR caused by parened initializer vs  prototype/typename
  590.     state: 758
  591.  
  592. 5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  593.     states: 395, 621, 1038, 1102, 1103
  594.  
  595. In  each  case  the  conflicts are resolved in favor of a declaration.  
  596. Note  that  this  decision  is  made  when  the  "declarator"  *seems* 
  597. complete.  Typically this takes place when a character (such as a ')', 
  598. ',', or '=') that terminates a declarator or abstractor declarator  is 
  599. seen.  At  such  a  point,  an  my LR(1) grammar makes the decision to 
  600. support a declaration/type-name assuming it is possible.   (The  added 
  601. complexity of the LALR-only conflicts discussed in the next section). 
  602.  
  603. Note  that  this disambiguation (provided by my grammar) is *NOT* what 
  604. is suggested in the ARM.   The  ARM  suggests  what  some  folks  have 
  605. referred  to  as "advanced parsing techniques" be used to disambiguate 
  606. based on first "pre-parsing" arbitrarily far ahead.  This approach  is 
  607. actually  not  "advanced  parsing", rather it is a through back to the 
  608. days before parsing was understood, and exponential search  algorithms 
  609. were  proposed  as  "parsing techniques." Currently, cfront supports a 
  610. hacked partial look-ahead technique, that alternately  "disambiguates" 
  611. hard  examples  and  "core-dumps"  for  others.  To date, I know of no 
  612. implementation  that  actually   comes   near   matching   the   ARM's 
  613. specification,   and   I  suspect  that  attempts  to  implement  such 
  614. conformance will lead to many buggy compilers,  that  support  varying 
  615. degrees  of  compliance  with  such ad-hoc requests for parsing.  Only 
  616. time will tell whether  the  ANSI  C++  committee  will  support  this 
  617. unimplemented  disambiguation technique.  Most users of cfront *think* 
  618. that the ARM is implemented in cfront, and that cfront implements  the 
  619. ARM.   This  area  of ambiguity not only demonstrates cfront's lack of 
  620. compliance  with  the  ARM,  but  also   exemplifies   some   of   the 
  621. unimplemented technology that is proposed in the ARM.
  622.  
  623.  
  624. LALR-only CONFLICTS IN THE GRAMMAR
  625.  
  626. As  can  be seen in the analysis of the grammar in y.output, there are 
  627. some  LALR-only  conflict  contexts  in  some  of  the   reduce/reduce 
  628. conflicts.   Since yacc disambiguates in favor of lower numbered rules 
  629. during  R/R  conflict,  most  of   these   LALR-only   conflicts   are 
  630. insignificant  (see  autodoc5.txt  for  discussion  of  this concept). 
  631. Specifically, when the left context *requires* unambiguously that that 
  632. a certain reduction take place, and the parser was going  to  do  that 
  633. reduction   anyway   (by  default),  then  the  LALR-only  problem  is 
  634. insignificant.  Based on the above reasoning, the LALR-only  conflicts 
  635. in the following states are insignificant:
  636.  
  637.     states: 738(mostly), 739, 740, 1105
  638.  
  639. The  states where there are real LALR-only conflicts with significance 
  640. are:
  641.     
  642.     state 738 on ',' and '='
  643.  
  644.     state 758 on ',' and '='
  645.  
  646. The significant subsets of the unambiguous left context trees  (copied 
  647. from the y.output file) are:
  648.  
  649.  
  650. LALR-only conflict contexts leading to state 738 and lookahead symbol <','>
  651.     Possible reductions rules include (61,73)
  652.         type_qualifier_list_opt : (61)
  653.         postfix_expression : TYPEDEFname '(' ')' (73)
  654.  
  655. --738+-1014--952+-837(73)    $start IDENTIFIER '{' ! CLCL TYPEDEFname '(' TYPEDEFname '(' ')'
  656.      |          --835(73)    $start IDENTIFIER '{' TYPEDEFname ! '(' TYPEDEFname '(' ')'
  657.      |
  658.      --748(73)    $start IDENTIFIER '(' '(' TYPEDEFname ! '(' ')'
  659.  
  660.  
  661. LALR-only conflict contexts leading to state 738 and lookahead symbol <'='>
  662.     Possible reductions rules include (61,73)
  663.         type_qualifier_list_opt : (61)
  664.         postfix_expression : TYPEDEFname '(' ')' (73)
  665.  
  666. --738+-1014--952(73)    $start IDENTIFIER '{' TYPEDEFname '(' ! TYPEDEFname '(' ')'
  667.      |
  668.      --748(73)    $start IDENTIFIER '(' '(' TYPEDEFname ! '(' ')'
  669.  
  670.  
  671. LALR-only conflict contexts leading to state 758 and lookahead symbol <','>
  672.     Possible reductions rules include (61,74)
  673.         type_qualifier_list_opt : (61)
  674.         postfix_expression : global_or_scoped_typedefname '(' ')' (74)
  675.  
  676. --758--754(74)    $start IDENTIFIER '(' '(' ! CLCL TYPEDEFname '(' ')'
  677.  
  678.  
  679. LALR-only conflict contexts leading to state 758 and lookahead symbol <'='>
  680.     Possible reductions rules include (61,74)
  681.         type_qualifier_list_opt : (61)
  682.         postfix_expression : global_or_scoped_typedefname '(' ')' (74)
  683.  
  684. --758--754(74)    $start IDENTIFIER '(' '(' ! CLCL TYPEDEFname '(' ')'
  685.  
  686.  
  687. As explained in the description of the "sample sentence" that is given 
  688. for  each  context  (see  autodoc5.txt),  it  is not unique, and it is 
  689. *especially* non-unique to the left of  the  '!'  symbol.   Never  the 
  690. less, it provides (most of the time) rapid insight into the conflicts, 
  691. which  makes  it  unnecessary to look at the details of the associated 
  692. demonstrations (also provided in the y.output file).
  693.  
  694. Looking at these examples, it  can  be  seen  that  in  each  case,  a 
  695. parenthesized  type  name  is  created,  and  a trailing ',' or '=' is 
  696. found.  Since the type-name used in an old style cast  cannot  contain 
  697. such  symbols  as  ',' or '=' (unprotected by parens), the presence of 
  698. such a token  precludes  the  possibility  of  the  sequence  being  a 
  699. typename.  For example, looking at the left context for state 738 that 
  700. includes state 952, consider the fragment:
  701.  
  702.     struct  TYPE1 { ...... } ;
  703.     struct  TYPE2 { ...... } ;
  704.     main(){
  705.         TYPE1 ( ( TYPE2()
  706.  
  707.  
  708. There  is  a chance that TYPE2 is about to be redeclared at this inner 
  709. scope.  In such a case the fragment might continue:
  710.  
  711.  
  712.     struct  TYPE1 { ...... } ;
  713.     struct  TYPE2 { ...... } ;
  714.     main(){
  715.         TYPE1 ( ( TYPE2()));
  716.         }
  717.  
  718. with lots of redundant parents around the redeclared "TYPE2".   As  an 
  719. alternative, the fragment might continue:
  720.  
  721.     struct  TYPE1 { ...... } ;
  722.     struct  TYPE2 { ...... } ;
  723.     main(){
  724.         TYPE1 ( ( TYPE2() + 10));
  725.  
  726. and  become an expression.  The problematic situation is provided when 
  727. (for example) a ',' follows:
  728.  
  729.     struct  TYPE1 { ...... } ;
  730.     struct  TYPE2 { ...... } ;
  731.     main(){
  732.         TYPE1 ( ( TYPE2() , 
  733.  
  734. Clearly, as provided in the analysis, this must be a case  where  only 
  735. an  expression  can  result,  as a ',' could not be placed as shown if 
  736. TYPE2 were being redeclared.
  737.  
  738. Careful consideration of each of the other LALR-only conflicts reveals 
  739. an identical fundamental problem.
  740.  
  741. As is the basis for all  LALR-only  contexts,  there  are  some  other 
  742. contexts  where this same LALR states 738 is used with a trailing ',', 
  743. and it is possible for the item to  the  left  of  the  ','  to  be  a 
  744. declarator  (specifically,  when the declarator is the first type in a 
  745. prototype list, a comma may follow it).  Interestingly,  this  precise 
  746. problem  is also the reason for the '=' look-ahead problem, as '=' may 
  747. be used to specify an initializer in a prototype list, but  can  never 
  748. be  found  in  an abstract declarator (as is required for an old style 
  749. cast typename), or  adjacent  to  a  simple  declaration's  declarator 
  750. *while* nested within parenthesis.
  751.  
  752. With  this  insight, it is not difficult to change the grammar so that 
  753. the critical rules are repeated for these two distinct contexts.  As I 
  754. mentioned in my autodoc5.txt file,  I  am  working  on  a  subtle  and 
  755. automated  method  for  removing  these  LALR-only conflicts.  I would 
  756. prefer (for now) to leave these conflicts in place and remove them via 
  757. subtle  means,  rather  than  by  brute   replications   of   critical 
  758. reductions.   Since  the nesting complexities of these scenarios seems 
  759. large (re: function like cast of function like cast  etc.),  I  expect 
  760. that  leaving  these  conflicts  in  the  grammar will have no adverse 
  761. effects on users with real code.   Recall  that  the  worst  that  can 
  762. happen  with  such  conflicts  remaining  is that an expression can be 
  763. signaled as a syntax error, when in fact it is "unambiguous", based on 
  764. one token of look-ahead.
  765.  
  766.  
  767. SAMPLE RESOLUTIONS OF AMBIGUITIES BY MY C++ GRAMMAR
  768.  
  769. Since my grammar tends to disambiguate "prematurely" (i.e., the parser 
  770. does not use infinite lookahead) when compared with the ARM  standard, 
  771. it tends to force non-declarations into being declarations.  Later on, 
  772. when   the   tokens  appear  that  require  an  interpretation  as  an 
  773. expression, a syntax error results.  Hence, the  "hard  examples"  are 
  774. those   in   which  the  disambiguating  tokens  appear  late  in  the 
  775. expressions.
  776.  
  777. Of the "hard examples" given in the ARM (r6.8), my  grammar  can  only 
  778. "properly" detect a "statement-expression" for the stream:
  779.  
  780.         T(a,5)>>c;
  781.  
  782. All  the  other  examples  default  to  a declarator after the closing 
  783. parenthesis  following  the  identifier.   (See  my  comments  in  the 
  784. conclusion section of this paper).
  785.  
  786. I  actually  am  not sure I agree with all the examples in the C++ 2.0 
  787. Reference Manual. Specifically, the example in section 6.8:
  788.  
  789.         T (*d) (double(3));  // expression statement
  790.  
  791. In the example "T"  is  specified  to  be  a  simple-type-name,  which 
  792. includes  all  the  basic  types  as  well  as  class-names, and more. 
  793. Considering the following are valid declarations:
  794.  
  795.         void *a (0);
  796.         void *b (int(0));
  797.         void (*c)(int(0));
  798.  
  799. I am unable to see the "syntactic" difference between this last  token 
  800. stream  and  the  example  just  cited  in  the  reference manual.  My 
  801. simplistic parser gives me the result that  I  at  least  expect.   It 
  802. concludes  (prematurely, but seemingly correctly) that the stream is a 
  803. declaration (with a new style initializer).
  804.  
  805. As a positive note, my grammar is able to parse the  example  given  a 
  806. while back in comp.lang.c++, that Zortech C++ 1.07 could not parse:
  807.  
  808.         a = (double(a)/double(b))...;
  809.  
  810. Apparently,   upon   seeing   "(double"   some  parsers  commit  to  a 
  811. parenthesized type-name for a cast expression, and cannot  proceed  to 
  812. parse  a  parenthesized  expression.   No  mention  of this problem is 
  813. listed in my conflict list, as resolution of this problem is simply  a 
  814. matter of letting the LR parser wait long enough before committing. My 
  815. grammar commits when it sees "a" in "(a)" to providing an expression.
  816.  
  817.  
  818. DIFFICULT AMBIGUITIES FOR A "C++ 2.0" COMPATIBLE PARSER TO TRY
  819.  
  820. Having seen the above contexts, I would be curious to see if other C++ 
  821. front  ends  with  "smart  lexers"  (such  as  cfront)  can handle the 
  822. following.   These  examples  are  not  guaranteed  to  be   evaluated 
  823. correctly  by  my grammar, but I expect them to demonstrate weaknesses 
  824. in many other parsers.  The interpretation of these examples  per  C++ 
  825. 2.0 definitions requires massive lookahead.  In addition, the examples 
  826. are  generally unreadable by humans, and rarely parsed the same way by 
  827. any two implementations.
  828.  
  829.     main()
  830.       {
  831.       class T 
  832.         { 
  833.         /* ... */
  834.         } a;
  835.       typedef T T1,T2,T3,T4,T5,T7,T8,T9,Ta,Tb,Tc,Td;
  836.         { /* start inner scope */
  837.         T((T1)         ); // declaration
  838.         T((T2)    a    ); // Statement expression
  839.         T((T3)(       )); // declaration of T3
  840.         T((T4)(T      )); // declaration of T4
  841.         T((T5)(T  a   )); // declaration of T5
  842.         T((T6)(T((a) ))); // declaration of T6
  843.         T((T7)(T((T) ))); // declaration of T7
  844.         T((T8)(T((T)b))); // statement expression
  845.  
  846.         T(b[5]); // declaration
  847.         T(c());  // declaration
  848.         T(d()[5]);  // statement expression ? (function returning array 
  849.                       // is semantically illegal, but syntactically proper)
  850.         T(e[5]());  // statement expression ? (No array of functions)
  851.         T(f)[5]();  // statement expression ?  "                   "
  852.         
  853.         T(*Ta() )[5] [4];  //declaration
  854.         T(*Tb() [5]) [4];  //statement expression ? (function returning array)
  855.  
  856.         T(*Tc()) [3 +2];  //declaration
  857.         T(*Td()) [3 ]+2;  //statement expression
  858.  
  859.         }
  860.       }        
  861.  
  862.  
  863. COMMENTARY ON C++ 2.0 DISAMBIGUATING RULES
  864.  
  865. There are two distinct thrusts in conflict disambiguation as  provided 
  866. by  AT&T's  efforts to define a standard for C++.  The first thrust is 
  867. "parse tokens into the longest possible declarator, and  identify  the 
  868. syntax  errors  that  result".   The  second thrust is to "use massive 
  869. external technology ("smart lexer", a.k.a.: "recursive  decent  parser 
  870. that  helps  the  lexer",  a.k.a.   LALEX)  to look ahead, so that the 
  871. parser doesn't mis-parse a function-like-cast  as  a  declaration  and 
  872. induce  a  syntax  error".   The  first  is  a commitment to LR parser 
  873. technology, and an existing grammar (which could be cleaned up).   The 
  874. second  is  a commitment to NOT use an LR parser, and to the use of an 
  875. existing implementation.
  876.  
  877. It is my belief that LR parsers are well understood, and the  addition 
  878. of a "smart lexer" destroys all structure in a parser.  The result can 
  879. be anticipated to become a quagmire of code and hacks.  With this firm 
  880. conviction,  I  have  provided my grammar in the hopes that a standard 
  881. can emerge that IS well defined, and is implementable, and is readable 
  882. by humans.
  883.  
  884.  
  885. SOURCE OF CONFLICTS IN C++ (MIXING TYPES AND EXPRESSIONS)
  886.  
  887. One fundamental strength in C is the similarity  between  declarations 
  888. and  expressions.   The  syntax  of  the  two  is  intended to be very 
  889. similar, and the result is a clean declaration and expression  syntax. 
  890. (It  takes  some  getting  used  to,  but  it  is in my opinion good).  
  891. Unfortunately, there are some slight distinctions  between  types  and 
  892. expressions,  which  Ritchie  et.  al.  apparently noticed.  It is for 
  893. this reason (I am guessing) that the C cast operator REQUIRES that the 
  894. type be enclosed in parenthesis.  Moreover,  there  is  also  a  clear 
  895. separator in a declaration between the declarator and the initializing 
  896. expression  (the  '=') (as some of you know, there is some interesting 
  897. history  in  this  area.).   The  bottom  line  (as  seen  with  20-20 
  898. hindsight)  is:  "keep  declarations  and expressions separate".  Each 
  899. violation of this basic rule has induced conflicts.
  900.  
  901.  
  902. To be concrete about the differences between  types  and  expressions, 
  903. the following two distinctions are apparent:
  904.  
  905.     1)  Abstract declarators are permitted.  No analogy is provided in 
  906.     expressions.  The notable distinction is that abstract declarators 
  907.     include the possibility of trailing '*' tokens.
  908.         
  909.     2) The binding of elements in a declaration is very different from 
  910.     any expression.  Notably,  the  declaration-specifiers  are  bound 
  911.     separately  to  each  declarator  in  the  comma separated list of 
  912.     declarators (example:  int  a,  b,  c;).   With  (most  forms  of) 
  913.     expressions,   a   comma   provides   a  major  isolation  between 
  914.     expressions.
  915.  
  916. C also used  reserved  names  to  GREATLY  reduce  the  complexity  of 
  917. parsing.   The  introduction of typedef names increased the complexity 
  918. (it made the language context sensitive), but a  simple  hack  between 
  919. lex and YACC overcame the problem.  An example is the statement:
  920.  
  921.         name (*b)[4];
  922.  
  923. Note  that  this  is  ambiguous,  EVEN  in  ANSI  C,  IF  there  is no 
  924. distinction between type-names and function names!  (i.e.,  "b"  could 
  925. be getting redeclared to be of type "pointer to array of name", OR the 
  926. function  "name"  could  be  called  with argument "*b", the result of 
  927. which is indexed to the 4th element). In C, the  two  kinds  of  names 
  928. (TYPEDEFnames and function names (a.k.a.: declared identifiers)) share 
  929. a  name  space,  and  at  every  point  in a source program the (hack) 
  930. contextual distinction can be made by the tokenizer.  Hacks  are  neat 
  931. things in that the less you use them, the more likely they are to work 
  932. when you REALLY need them (i.e., you don't have to fight with existing 
  933. hacks).   Having  worked on designing and implementing a C compiler, I 
  934. was pleasantly amazed at how the constructs all fell together.
  935.  
  936. The major violations of this approach (i.e., keep declaration separate 
  937. from expressions) that come to mind with C++ are: 
  938.  
  939.         function-like-casts,
  940.         freestore expressions without parens around the type,
  941.         conversion function names using arbitrary type specifiers,
  942.         parenthesized initializers that drive constructors.
  943.  
  944. The last problem, parenthesized initializers, provides  two  areas  of 
  945. conflicts.  The first is really an interference issue with old style C 
  946. function  definitions,  which  only bothers folks at file scope (GNU's 
  947. G++ compiler considered this to be too great  an  obstacle,  and  they 
  948. don't currently support old style C definitions!).  The second part of 
  949. this   conflict   involves   a  more  subtle  separation  between  the 
  950. declarator, and the initializer. (K&R  eventually  provided  an  equal 
  951. sign  as  an unequivocal separator, but parens used in C++ are already 
  952. TOO overloaded to separate anything).  The significance of  this  lack 
  953. of  a  clear  separator  is  that  it  is difficult to decide that the 
  954. "declarator" is complete, and that the declared name should  be  added 
  955. to  the scope.  The last problem does interact in a nasty way with the 
  956. function-like cast vs declaration conflicts  (the  problem  slows  the 
  957. feedback  loop  to  the  symbol  table, which is critical to continued 
  958. lexing).  The parened initializers also provide another context  where 
  959. it  is  difficult  to distinguish between expressions (a true argument 
  960. list for the constructor) and a declaration continuation (a  parameter 
  961. type list).  
  962.  
  963. The  second  problem  listed falls out of the "new-expression" with an 
  964. unparenthesized type.  This form of freestore (such as "new int *  *") 
  965. allows  types  to  be placed adjacent to expressions, and the trailing 
  966. '*' ambiguity rears its head.  I can easily prove  that  this  is  the 
  967. culprit  in  terms  of  specific  ambiguities,  in that removing these 
  968. (unnecessary?) forms significantly disambiguates the grammar.  (It  is 
  969. rather  nice  to  use  YACC  as  a  tool  to  prove  that a grammar is 
  970. unambiguous!).  It is interesting to note that if only the  derivation 
  971. of  a  freestore  expression  were  limited to (using the non-terminal 
  972. names of the form that the C++ Reference manual uses):
  973.  
  974.         new placement-opt ( type-name )  parened-arg-list-opt
  975.  
  976. then all the LR(1)  reduce  conflicts  based  on  this  problem  would 
  977. vanish.  Indeed, the culprit can clearly be shown to be:
  978.  
  979.         new placement-opt  restricted-type-name parened-arg-list-opt
  980.  
  981. The  characters  which  excite  these reduction conflicts are '*', and 
  982. '&'.
  983.  
  984. The    third    problem    that    I    indicated     involves     the 
  985. conversion-function-name.   Here  again, if the syntax were restricted 
  986. to ONLY:
  987.  
  988.         operator simple-type-name
  989.  
  990. then the LR(1) conflicts would vanish.  It is interesting to note that 
  991. the  keyword  "operator"  serves  as  the  left  separator,  and   the 
  992. restriction   to  "simple-type-name"  results  in  an  implicit  right 
  993. separator  (simple-type-names  are  exactly  one  token  long).    The 
  994. conflicts  appear  when  multiple tokens are allowed for a declaration 
  995. specifier, and an optional pointer-modifier list may  be  added  as  a 
  996. postfix.   The  conflicts  that  result  from  this lack of separation 
  997. include all those provided by the freestore example.
  998.  
  999. Here again (as with the unambiguous version of freestore)  the  syntax 
  1000. could be extended to:
  1001.  
  1002. operator_function_name :
  1003.         OPERATOR any_operator
  1004.         | OPERATOR basic_type_name
  1005.         | OPERATOR TYPEDEFname
  1006.         | OPERATOR type_qualifier
  1007.         | OPERATOR '(' type_name ')'
  1008.         ;
  1009.  
  1010. instead of:
  1011.  
  1012. operator_function_name :
  1013.         OPERATOR any_operator
  1014.         | OPERATOR type_qualifier_list            operator_function_ptr_opt
  1015.         | OPERATOR non_elaborating_type_specifier operator_function_ptr_opt
  1016.         ;
  1017.  
  1018. and  the  ambiguities  would vanish (and the expressivity would not be 
  1019. diminished).
  1020.  
  1021.  
  1022. FUNCTION LIKE CAST vs DECLARATION AMBIGUITIES
  1023.  
  1024. The real big culprit (i.e., my anti-favorite) in this whole  ambiguity 
  1025. set   (re:   keeping   types   and   expressions   separate)   is  the 
  1026. function-like-cast.  The reason why it is so  significant  (to  an  LR 
  1027. parser)   is  that  the  binding  of  a  type-name,  when  used  in  a 
  1028. function-like-cast,  is  directly  to  the   following   parenthesized 
  1029. argument list.  In contrast, the binding of a type-name when used in a 
  1030. declaration  is to all the "stuff" that follows, up until a declarator 
  1031. termination mark like a ',', ';' or '='. Life really gets tough for LR 
  1032. folks when the parse stack MUST be reduced, but the parser just  can't 
  1033. tell  how  yet.  With this problem, the hacks began to appear (re: the 
  1034. "smart lexer").  Note that these new style casts are much more than  a 
  1035. notational  convenience  in  C++.   The necessity of the function like 
  1036. cast lies in the fact that such a cast  can  take  several  arguments, 
  1037. whereas the old style cast is ALWAYS a unary operator.
  1038.  
  1039. I was (past tense) actually working towards resolving this problem via 
  1040. some  standard  methods that I have developed (re: inline expansion of 
  1041. rules to provide deferred reduction).  I was (past tense)  also  using 
  1042. one  more  sneaky  piece  of  work  to  defer the reductions, as I was 
  1043. carefully making use of right recursion (instead of the standard  left 
  1044. recursion)  in  order  to  give  the  parser a chance to build up more 
  1045. context.  I can demonstrate the usefulness of right recursive grammars 
  1046. in disambiguating difficult toy grammars.  Unfortunately,  I  realized 
  1047. at  some  point  that I NEEDED to perform certain actions (such as add 
  1048. identifiers to the symbol table) in order  to  complete  the  parse!?!  
  1049. This  was  my catch 22.  I could POSSIBLY parse using an LALR grammar, 
  1050. if  I  could  only  defer  actions  until  I  had  enough  context  to 
  1051. disambiguate.   Unfortunately,  I  HAD to perform certain actions (re: 
  1052. modify the symbol table, which changed the action  of  the  tokenizer) 
  1053. BEFORE  I  could  continue to examine tokens!  In some terrible sense, 
  1054. the typedef hack had come back to haunt me.
  1055.  
  1056. I backed off a bit in my grammar after reaching this wall, and now  my 
  1057. grammar  only  waits  until  it reaches the identifier in the would be 
  1058. declarator.  I really  didn't  want  to  parse  the  stuff  after  the 
  1059. identifier  name  (sour  grapes?),  because  I  knew  I would not (for 
  1060. example) be able to identify  a  "constant  expression"  in  an  array 
  1061. subscript  (most of the time, if it isn't constant, then it can't be a 
  1062. declaration).  I don't believe that a compiler  should  compete  in  a 
  1063. battle  of  wits  with  the  programmer,  and  the  parser was already 
  1064. beginning to outwit me (i.e., I was having a hard time  parsing  stuff 
  1065. mentally that is provided as examples in the 2.0 Reference Manual.  In 
  1066. fact, many reviewers as well as the author had difficulty, and that is 
  1067. why errors appeared there originally, as well as in the ARM).
  1068.  
  1069.  
  1070. FUNCTION LIKE CAST vs DECLARATION : THE TOUGH EXAMPLE:        
  1071.         
  1072. The  following  is about the nastiest example that I have been able to 
  1073. construct for this ambiguity group.  I am presenting it here  just  in 
  1074. case someone is left with a thought that there is "an easy way out".
  1075.  
  1076. The   fact  that  identifiers  can  remain  ambiguous  SO  LONG  after 
  1077. encountering them can cause no end of  trouble  to  the  parser.   The 
  1078. following  example  does  not  succumb to static (re: no change to the 
  1079. symbol table)  anticipatory  lexing  of  a  statement.   As  such,  it 
  1080. demonstrates  the  futility  of  attempting  to use a "smart lexer" to 
  1081. support the philosophy: "If it can be interpreted  as  a  declaration, 
  1082. then so be it; otherwise it is an expression".  This ambiguous example 
  1083. exploits  the  fact that declarators MUST be added to the symbol table 
  1084. as  soon  as  they  are  complete  (and  hence  they   mask   external 
  1085. declarations).
  1086.  
  1087. First I will present the example without comments:
  1088.  
  1089. class Type1 {
  1090.             Type1 operator()(int);
  1091.             } ;
  1092. class wasType2 { ...}; 
  1093. int (*c2)(Type1 dummy);
  1094.  
  1095. main ()
  1096.     {
  1097.     const int    a1  = 0, new_var  (4), (*c1)(int     (a1));
  1098.     Type1       (a2) = 3, wasType2 (4), (*c2)(wasType2(a1));
  1099.     }
  1100.  
  1101.  
  1102.  
  1103.  
  1104. Now to repeat the example with comments:
  1105.  
  1106. class Type1 {....
  1107.             Type1 operator()(int);
  1108.             } ;
  1109. class wasType2 { ....}; /* we will almost redeclare this typename!?! */
  1110. int (*c2)(Type1 dummy); /* we will NOT redeclare Type1 */
  1111.  
  1112. main ()
  1113.     {
  1114.     /* The first line is indeed simple.  It is simply placed here
  1115.     to hint at how the second line MIGHT analogously be parsed. */
  1116.     
  1117.     const int    a1  = 0, new_var  (4), (*c1)(int     (a1));
  1118.  
  1119.     /*  As  a review, "a1" is declared to be a constant with value 0. 
  1120.         "new_var" is declared to be another constant, but with  value 
  1121.         4.  Finally,  "c1"  is  declared  to  be a pointer to a const 
  1122.         integer, and the initial value of this pointer is  "int(a1)", 
  1123.         which  is  the  same  as "int(0)", or simply "0" (a.k.a., the 
  1124.         null pointer). It is significant that "a1" entered the symbol 
  1125.         table  quickly  so  that  it  could  be  used  later  in  the 
  1126.         declaration. */
  1127.  
  1128.     /* Static lexing of what follows will suggest that the  following 
  1129.     is  also  a  declaration.   This  statement  is  actually 3 comma 
  1130.     separated expressions!! The explanation that follows  shows  that 
  1131.     assuming   the   2nd  statement  is  a  declaration  leads  to  a 
  1132.     contradiction. */
  1133.     
  1134.     Type1      (a2) = 3, wasType2 (4), (*c2)(wasType2(a1));
  1135.     
  1136.     /* Assume this second statement is a declaration.  Note  that  by 
  1137.     the  time  "c2" is parsed, "wasType2" has been redeclared to be a 
  1138.     variable of type "Type1".  Hence  "wasType2(a1)"  is  actually  a 
  1139.     function  call  to  "wasType2.operator()(a1)",  and  it  is not a 
  1140.     function    prototype    arg    list.     It     follows     that 
  1141.     "(*c2)(wasType2(a1))"  is  an  expression,  and NOT a declarator!  
  1142.     Since this last entry is not a declarator, the  entire  statement 
  1143.     must  be an expression (ugh! it is time to backtrack). After much 
  1144.     work on my part, I think it might even be  a  semantically  valid 
  1145.     expression.   Once this backtracking is complete, we see that the 
  1146.     first expression "Type1 (a2) = 3" is  an  assignment  to  a  cast 
  1147.     expression.  The second expression "wasType2 (4)", is a cast of a 
  1148.     constant.  The  third  expression  "(*c2)(wasType2(a1))",  is  an 
  1149.     indirect  function  call.  The argument of the call is the result 
  1150.     of a cast.  Note that "wasType2" is  actually  never  redeclared, 
  1151.     but it was close! */
  1152.     
  1153.     /*  For  those of you who can parse this stuff in your sleep, and 
  1154.     noticed the slight error  in  the  above  argument,  I  have  the 
  1155.     following "fix".  The error is that the 
  1156.  
  1157.         "(*c2)(wasType2(a1))" 
  1158.  
  1159.     could actually be a declaration with a parenthesized initializer.  
  1160.     I could have changed this token subsequence to:
  1161.  
  1162.         "(*(*c2)(wasType2(a1)))(int(a1))"
  1163.  
  1164.     and avoid the constructor ambiguity, but it would only complicate 
  1165.     the  discussion.   Note that in this form, if "wasType2" is not a 
  1166.     type, the the quoted text cannot be a declaration.*/
  1167.  
  1168.     /* Two parens are all a user would need to  add  to  the  cryptic 
  1169.     example  to  unambiguously  specify  that  this  statement  is an 
  1170.     expression.  Specifically: */
  1171.     
  1172.        (Type1) (a2) = 3, wasType2 (4), (*c2)(wasType2(a1));
  1173.     /* or ...*/
  1174.        (Type1 (a2) = 3), wasType2 (4), (*c2)(wasType2(a1));
  1175.  
  1176.     /* I would vote for a syntax error in such ambiguous stream, with 
  1177.     an  early  decision that it was a declaration.  After seeing this 
  1178.     example, I doubt that I could quickly assert that I could produce 
  1179.     a non-backtracking parser that disambiguates statements according 
  1180.     to the C++ 2.0 rule.  I am sure  I  can  forget  about  a  simple 
  1181.     lex-YACC combination doing it. */
  1182.  
  1183.     }
  1184.  
  1185.  
  1186. Most  simply  put,  if  a  "smart  lexer"  understands  these: a) I am 
  1187. impressed, b) Why use a parser when a lexer can parse so well?
  1188.  
  1189. The bottom line is that disambiguation of declarations via "If it  can 
  1190. be  a  declaration,  then  it is one", seems to require a backtracking 
  1191. parser. (Or some very fancy parsing approach).  I am not even sure  if 
  1192. the above examples are as bad as it can get!
  1193.  
  1194.  
  1195. CONCLUSION
  1196.  
  1197. I believe that the C++ grammar that I have made available represents a 
  1198. viable machine readable standard for the syntax description of the C++ 
  1199. language.   In  cases  where  the  ambiguities  are  still  exposed by 
  1200. conflicts (as noted by YACC), to further  defer  resolution  would  be 
  1201. detrimental  to  a  user.   I  see no benefit in describing a computer 
  1202. language that must support human writers, but cannot be understood  by 
  1203. humans.    Any   code   that  exploits  such  deferral  is  inherently 
  1204. non-portable, and deserves to be diagnosed as  an  error  (my  grammar 
  1205. asserts a "syntax error").  Rather than dragging the C++ language into 
  1206. support  for  a ad-hoc parser implementations such as what cfront (and 
  1207. the "smart lexer") have tried unsuccessfully  to  implement,  I  would 
  1208. heavily  suggest  the  use  of  my  grammar.  I do not believe that my 
  1209. grammar would "break" much existing code, but in cases where it would, 
  1210. the code would not be portable anyway (other than  to  a  port  of  an 
  1211. IDENTICAL parser).
  1212.  
  1213. I  hope  to see a great deal of use of my grammars, and I believe that 
  1214. standardizing on the represented syntax will unify  the  C++  language 
  1215. greatly.
  1216.  
  1217.         Jim Roskind
  1218.         Independent Consultant
  1219.         516 Latania Palm Drive
  1220.         Indialantic FL 32903
  1221.         (407)729-4348
  1222.         jar@hq.ileaf.com or ...uunet!leafusa!jar
  1223.  
  1224.  
  1225.  
  1226. APPENDIX A:
  1227.   PROPOSED GRAMMAR MODIFICATIONS (fixing '*', and '&' conflicts)
  1228.  
  1229. Based  on  the  other  items  described  above,  I  have the following 
  1230. suggestions for cleaning up the grammar definition.  Unfortunately, it 
  1231. provides subtle variations from the "C++ 2.0" standard.
  1232.  
  1233.  
  1234. Current Grammar:
  1235.  
  1236. operator_function_name :
  1237.         OPERATOR any_operator
  1238.         | OPERATOR type_qualifier_list            operator_function_ptr_opt
  1239.         | OPERATOR non_elaborating_type_specifier operator_function_ptr_opt
  1240.         ;
  1241.  
  1242.  
  1243. operator_new_type:
  1244.         type_qualifier_list              operator_new_declarator_opt
  1245.                         operator_new_initializer_opt
  1246.  
  1247.         | non_elaborating_type_specifier operator_new_declarator_opt
  1248.                         operator_new_initializer_opt
  1249.         ;
  1250.  
  1251. Proposed new grammar (which requires parens around complex types):
  1252.  
  1253. operator_function_name :
  1254.         OPERATOR any_operator
  1255.         | OPERATOR basic_type_name
  1256.         | OPERATOR TYPEDEFname
  1257.         | OPERATOR type_qualifier
  1258.         | OPERATOR '(' type_name ')'
  1259.         ;
  1260.  
  1261. operator_new_type:
  1262.         basic_type_name    operator_new_initializer_opt 
  1263.         | TYPEDEFname      operator_new_initializer_opt 
  1264.         | type_qualifier   operator_new_initializer_opt 
  1265.         | '(' type_name ') operator_new_initializer_opt 
  1266.         ;
  1267.  
  1268. The impact of the above changes is that all complex type names  (i.e.: 
  1269. names  that are not simply a typedef/class name, or a basic type names 
  1270. like char) must be enclosed in  parenthesis  in  both  `new  ...'  and 
  1271. `operator ...' expressions. Both of the above changes would clear up a 
  1272. number  of  ambiguities.   In some sense, the current "disambiguation" 
  1273. (of trailing '*', and '&') is really  a  statement  that  whatever  an 
  1274. LR(1)  parser cannot disambiguate is a syntax error.  In contrast, the 
  1275. above rules define an unambiguous grammar.
  1276.  
  1277.  
  1278.  
  1279. APPENDIX B:
  1280.     CANONICAL DESCRIPTION OF CONFLICTS and STATES
  1281.  
  1282.  
  1283. The following  is  directly  extracted  from  the  canonical  list  of 
  1284. conflicts  provided  in  the  y.output  file.   For  a  more  complete 
  1285. discussion of the significance of the canonical sentence provided with 
  1286. each state, see the autodoc5.txt file.  I have also  added  annotation 
  1287. to connect these sentence to the summary given earlier:
  1288.  
  1289. state 64: STRUCT IDENTIFIER  .  ':'    (1 reduction, or a shift)
  1290.     1 SR caused by member declaration of sub-structure, with trailing :
  1291.  
  1292. state 131: OPERATOR INT  .  '*'    (1 reduction, or a shift)
  1293.     8 SR caused by operator function name with trailing * or &
  1294.  
  1295. state 131: OPERATOR INT  .  '&'    (1 reduction, or a shift)
  1296.     8 SR caused by operator function name with trailing * or &
  1297.  
  1298. state 138: OPERATOR CONST  .  '*'    (1 reduction, or a shift)
  1299.     8 SR caused by operator function name with trailing * or &
  1300.  
  1301. state 138: OPERATOR CONST  .  '&'    (1 reduction, or a shift)
  1302.     8 SR caused by operator function name with trailing * or &
  1303.  
  1304. state 281: OPERATOR INT '*' CONST  .  '*'    (1 reduction, or a shift)
  1305.     8 SR caused by operator function name with trailing * or &
  1306.  
  1307. state 281: OPERATOR INT '*' CONST  .  '&'    (1 reduction, or a shift)
  1308.     8 SR caused by operator function name with trailing * or &
  1309.  
  1310. state 282: OPERATOR INT '*'  .  '*'    (1 reduction, or a shift)
  1311.     8 SR caused by operator function name with trailing * or &
  1312.  
  1313. state 282: OPERATOR INT '*'  .  '&'    (1 reduction, or a shift)
  1314.     8 SR caused by operator function name with trailing * or &
  1315.  
  1316. state 395: CLCL TYPEDEFname '(' TYPEDEFname  .  ')'    (1 reduction, or a shift)
  1317.     5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  1318.     Make declaration rather than expression.
  1319.  
  1320.     problem: Constructor with anonymous arg name at file scope
  1321.         looks like redeclaration of typename.
  1322.  
  1323.         A::B(C){}  should be the same as  A::B(C x){}  
  1324.         (but it isn't for an LR(1) grammar)
  1325.  
  1326. state 536: IDENTIFIER '(' '~' TYPEDEFname  .  '('    (1 reduction, or a shift)
  1327.     1 SR caused by explicit call to destructor, without explicit scope
  1328.  
  1329. state 571: IDENTIFIER '(' NEW INT  .  '*'    (1 reduction, or a shift)
  1330.     8 SR caused by freestore              with trailing * or &
  1331.  
  1332. state 571: IDENTIFIER '(' NEW INT  .  '&'    (1 reduction, or a shift)
  1333.     8 SR caused by freestore              with trailing * or &
  1334.  
  1335. state 572: IDENTIFIER '(' NEW CONST  .  '*'    (1 reduction, or a shift)
  1336.     8 SR caused by freestore              with trailing * or &
  1337.  
  1338. state 572: IDENTIFIER '(' NEW CONST  .  '&'    (1 reduction, or a shift)
  1339.     8 SR caused by freestore              with trailing * or &
  1340.  
  1341. state 621: CLCL TYPEDEFname '(' TYPEDEFname '[' ']'  .  ')'    (1 reduction, or a shift)
  1342.     5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  1343.     Make declaration rather than expression.
  1344.     Don't form an old style cast.
  1345.  
  1346. state 738: IDENTIFIER '(' TYPEDEFname '(' ')'  .  ')'    (2 reductions)
  1347.     3 RR caused by function-like cast vs typedef redeclaration ambiguity
  1348.     LALR-only can be ignored.
  1349.     Make declaration rather than expression.
  1350.  
  1351. state 738: IDENTIFIER '(' TYPEDEFname '(' ')'  .  ','    (2 reductions)
  1352.     3 RR caused by function-like cast vs typedef redeclaration ambiguity
  1353.     Problem with LALR-only conflict.
  1354.     Make declaration rather than expression.
  1355.  
  1356. state 738: IDENTIFIER '(' TYPEDEFname '(' ')'  .  '='    (2 reductions)
  1357.     3 RR caused by function-like cast vs typedef redeclaration ambiguity
  1358.     Problem with LALR-only conflict.
  1359.     Make declaration rather than expression.
  1360.  
  1361. state 739: IDENTIFIER '(' TYPEDEFname '(' IDENTIFIER  .  '('    (2 reductions)
  1362.     3 RR caused by function-like cast vs identifier declaration ambiguity
  1363.     Make declaration rather than expression.
  1364.  
  1365. state 739: IDENTIFIER '(' TYPEDEFname '(' IDENTIFIER  .  ')'    (2 reductions)
  1366.     3 RR caused by function-like cast vs identifier declaration ambiguity
  1367.     LALR-only can be ignored.
  1368.     Make declaration rather than expression.
  1369.  
  1370. state 739: IDENTIFIER '(' TYPEDEFname '(' IDENTIFIER  .  '['    (2 reductions)
  1371.     3 RR caused by function-like cast vs identifier declaration ambiguity
  1372.     Make declaration rather than expression.
  1373.  
  1374. state 740: IDENTIFIER '(' TYPEDEFname '(' '~' TYPEDEFname  .  '('    (2 reductions)
  1375.     3 RR caused by destructor declaration vs destructor call 
  1376.     Make declaration of destructor rather than expression.
  1377.  
  1378. state 740: IDENTIFIER '(' TYPEDEFname '(' '~' TYPEDEFname  .  ')'    (2 reductions)
  1379.     3 RR caused by destructor declaration vs destructor call 
  1380.     LALR-only can be ignored.
  1381.     Make declaration of destructor rather than expression.
  1382.  
  1383. state 740: IDENTIFIER '(' TYPEDEFname '(' '~' TYPEDEFname  .  '['    (2 reductions)
  1384.     3 RR caused by destructor declaration vs destructor call 
  1385.     Make declaration of destructor rather than expression.
  1386.  
  1387. state 758: IDENTIFIER '(' CLCL TYPEDEFname '(' ')'  .  ')'    (2 reductions)
  1388.     3 RR caused by parened initializer vs prototype/typename
  1389.     Make declaration rather than expression.
  1390.  
  1391. state 758: IDENTIFIER '(' CLCL TYPEDEFname '(' ')'  .  ','    (2 reductions)
  1392.     3 RR caused by parened initializer vs prototype/typename
  1393.     Problem with LALR-only conflict.
  1394.     Make declaration rather than expression.
  1395.  
  1396. state 758: IDENTIFIER '(' CLCL TYPEDEFname '(' ')'  .  '='    (2 reductions)
  1397.     3 RR caused by parened initializer vs prototype/typename
  1398.     Problem with LALR-only conflict.
  1399.     Make declaration rather than expression.
  1400.  
  1401. state 778: IDENTIFIER '(' NEW INT '*' CONST  .  '*'    (1 reduction, or a shift)
  1402.     8 SR caused by freestore              with trailing * or &
  1403.  
  1404. state 778: IDENTIFIER '(' NEW INT '*' CONST  .  '&'    (1 reduction, or a shift)
  1405.     8 SR caused by freestore              with trailing * or &
  1406.  
  1407. state 779: IDENTIFIER '(' NEW INT '*'  .  '*'    (1 reduction, or a shift)
  1408.     8 SR caused by freestore              with trailing * or &
  1409.  
  1410. state 779: IDENTIFIER '(' NEW INT '*'  .  '&'    (1 reduction, or a shift)
  1411.     8 SR caused by freestore              with trailing * or &
  1412.  
  1413. state 1038: IDENTIFIER '{' TYPEDEFname '(' '(' TYPEDEFname  .  ')'    (1 reduction, or a shift)
  1414.     5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  1415.     Make declaration rather than expression.
  1416.  
  1417. state 1100: IDENTIFIER '{' IF '(' IDENTIFIER ')' ';'  .  ELSE    (1 reduction, or a shift)
  1418.     1 SR caused by dangling else and my laziness
  1419.  
  1420. state 1102: IDENTIFIER '{' TYPEDEFname '(' '(' TYPEDEFname '[' ']'  .  ')'    (1 reduction, or a shift)
  1421.     5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  1422.     Make declaration rather than expression.
  1423.  
  1424. state 1103: IDENTIFIER '{' TYPEDEFname '(' '*' '(' TYPEDEFname  .  ')'    (1 reduction, or a shift)
  1425.     5 SR caused by redundant parened TYPEDEFname redeclaration vs old style cast
  1426.     Make declaration rather than expression.
  1427.  
  1428. state 1105: STRUCT IDENTIFIER '{' TYPEDEFname '(' TYPEDEFname ')'  .  ';'    (2 reductions)
  1429.     6 RR caused by constructor declaration vs member declaration
  1430.  
  1431. state 1105: STRUCT IDENTIFIER '{' TYPEDEFname '(' TYPEDEFname ')'  .  '{'    (2 reductions)
  1432.     6 RR caused by constructor declaration vs member declaration
  1433.  
  1434. state 1152: STRUCT IDENTIFIER '{' TYPEDEFname '(' TYPEDEFname '[' ']' ')'  .  ';'    (2 reductions)
  1435.     6 RR caused by constructor declaration vs member declaration
  1436.  
  1437. state 1152: STRUCT IDENTIFIER '{' TYPEDEFname '(' TYPEDEFname '[' ']' ')'  .  '{'    (2 reductions)
  1438.     6 RR caused by constructor declaration vs member declaration
  1439.  
  1440. state 1175: STRUCT IDENTIFIER '{' EXTERN INT '(' TYPEDEFname '[' ']' ')'  .  ';'    (2 reductions)
  1441.     6 RR caused by constructor declaration vs member declaration
  1442.  
  1443. state 1175: STRUCT IDENTIFIER '{' EXTERN INT '(' TYPEDEFname '[' ']' ')'  .  '{'    (2 reductions)
  1444.     6 RR caused by constructor declaration vs member declaration
  1445.  
  1446.